//! @Author: DengLibin
//! @Date: Create in 2024-01-10 11:47:51
//! @Description: 定时任务

use std::{str::FromStr, time::Duration};

use chrono::Utc;
use chrono_tz::Tz;
use cron::Schedule;
use log::info;
use tokio::time::Instant;

use crate::{
    common_result::{to_common_result, CommonResult},
    date,
};

/// @Author: DengLibin
/// @Date: Create in 2024-01-10 11:59:27
/// @Description: demo
pub fn demo() {
    //               sec  min   hour   day of month   month   day of week   year
    let expression = "0   30   9,12,15     1,15       May-Aug  Mon,Wed,Fri  2018/2";
    let schedule = Schedule::from_str(expression).unwrap();
    println!("Upcoming fire times:");
    for datetime in schedule.upcoming(Utc).take(10) {
        println!("-> {}", datetime);
    }
}
/// @Author: DengLibin
/// @Date: Create in 2024-01-11 12:24:38
/// @param: cron_expression 定时表达式 如: 0/5 * * * * *(每5秒执行一次) ，0 19 12 * * ?(每天12点19分)
/// @Description: 调用该函数,根据定时表达式 判断下个执行时间点,时间到了该函数才返回
pub async fn next_execute_point(cron_expression: &str) -> CommonResult<()> {
    // 解析 cron 表达式
    let r: Result<Schedule, cron::error::Error> = Schedule::from_str(cron_expression);
    let schedule = to_common_result(r)?;

    let next_execution: Option<chrono::prelude::DateTime<Tz>> =
        schedule.upcoming(Tz::Asia__Shanghai).next();
    if let Some(next_time) = next_execution {
        info!("下个执行点:{}", next_time);
        let timestamp = next_time.timestamp_millis() as u64;
        let now_stamp = date::get_sys_timestamp_millis() as u64;
        let op_i = Instant::now().checked_add(Duration::from_millis(timestamp - now_stamp));
        if let Some(i) = op_i {
            tokio::time::sleep_until(i).await;
        }
    }

    Ok(())
}

pub async fn loop_execute_point(cron_expression: &str) -> CommonResult<()> {
    // 解析 cron 表达式
    let r: Result<Schedule, cron::error::Error> = Schedule::from_str(cron_expression);
    let schedule = to_common_result(r)?;
    loop {
        let next_execution: Option<chrono::prelude::DateTime<Tz>> =
            schedule.upcoming(Tz::Asia__Shanghai).next();
        if let Some(next_time) = next_execution {
            info!("下个执行点:{}", next_time);
            let timestamp = next_time.timestamp_millis() as u64;
            let now_stamp = date::get_sys_timestamp_millis() as u64;
            let op_i = Instant::now().checked_add(Duration::from_millis(timestamp - now_stamp));
            if let Some(i) = op_i {
                tokio::time::sleep_until(i).await;
            }
        }
    }

    Ok(())
}
